#include "head.h"
#define RED "\033[1;31m"
#define RESET "\033[0m"

void display() {
    const char *text_art[] = {
        "    _   ______________   ____  _________ __ __ ",
        "   / | / / ____/_  __/  / __ \\/  _/ ___// //_/ ",
        "  /  |/ / __/   / /    / / / // / \\__ \\/ ,<    ",
        " / /|  / /___  / /    / /_/ // / ___/ / /| |   ",
        "/_/ |_/_____/ /_/    /_____/___//____/_/ |_|   "
    };

    int rows = sizeof(text_art) / sizeof(text_art[0]);
    for (int i = 0; i < rows; i++) {
        printf(RED "%s\n" RESET, text_art[i]);
    }
}

typedef struct{
    int signal;
    char buf[1024];
}stdin_msg;

int pipe_fd[2];
int exit_flag = 0;

void func1(int num){
    exit_flag = 1;
}
int main(int argc,char*argv[])
{
    display();
    pipe(pipe_fd);
    if(fork() != 0){
        struct sigaction act, old;
        bzero(&act, sizeof(act));
        act.sa_handler = func1;
        sigaction(2, &act, &old);
        stdin_msg msg;
        msg.signal = 0;
        while(1){
            bzero(msg.buf, sizeof(msg.buf));
            read(STDIN_FILENO, msg.buf, sizeof(msg.buf));
            if(exit_flag == 1){
                msg.signal = 2;
                write(pipe_fd[1], &msg, sizeof(msg));
                break;
            }
            write(pipe_fd[1], &msg, sizeof(msg));
        }
        printf("准备退出\n");
        wait(NULL);
        return 0;
    }
    setpgid(0, 0);

    // 判断登录信息格式
    if(strcmp(argv[1], "-u") != 0 || strcmp(argv[3], "-p") != 0){  
        printf("登录信息格式有误, 请重新登录.\n");
        return 0;
    }
    // 再判断用户名是否有特殊字符
    for(int i=0; i<strlen(argv[2]); i++){
        //printf("第%d个字符为: %c\n", i, argv[2][i]);
        if((argv[2][i] < '0' || argv[2][i] > '9') && 
           (argv[2][i] < 'A' || argv[2][i] > 'Z') && 
           (argv[2][i] < 'a' || argv[2][i] > 'z')){
            printf("用户名只能使用数字和字母, 不能使用特殊字符.\n");
            return 0;
        }
    }
    // 绑定ip和端口
    char ip[100] = {0};
    load_config("ip", ip);
    char port[100] = {0};
    load_config("port", port);

    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(port));
    addr.sin_addr.s_addr = inet_addr(ip);

    connect(socket_fd, (struct sockaddr *)&addr, sizeof(addr));
    // 初始化请求报文
    request_t *req = (request_t *)malloc(sizeof(request_t));
    memset(req, 0, sizeof(request_t));
    strcpy(req->path, "/");
    response_t *res = (response_t *)malloc(sizeof(response_t));
    memset(res, 0, sizeof(response_t));

    thread_status *pthread_info = (thread_status *)malloc(sizeof(thread_status));
    pthread_info->length = 3;
    pthread_mutex_t lock;
    pthread_mutex_init(&lock, NULL);
    pthread_info->lock = lock;
    pthread_info->thread_ids = (pthread_t*)calloc(3, sizeof(pthread_t));
    pthread_info->status = (int*)calloc(3, sizeof(int));

    // 是否已经登录
    int is_login = 0;

    if(login(req, res, argv, socket_fd) != 0){
        is_login = 0;
        printf("%s\n", res->args);
        printf("登录失败.\n");
        return 0;
    }

    is_login = 1;
    strcpy(req->token, res->args);
    printf("token: %s\n", req->token);

    int epfd = epoll_create(1);
    // 添加监听事件: 标准输入
    struct epoll_event event;
    event.events = EPOLLIN;
    //event.data.fd = STDIN_FILENO;
    //epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &event );
    // 添加监听事件: socket的接收数据(读就绪)
    event.data.fd = socket_fd;
    epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &event );
    event.data.fd = pipe_fd[0];
    epoll_ctl(epfd, EPOLL_CTL_ADD, pipe_fd[0], &event );

    //当是登陆状态
    while (is_login == 1)
    {
        memset(req->args, 0, sizeof(req->args));
        printf("\033[1;46;37mclient@%s%s$ \033[0m", req->user_name, req->path);
        fflush(stdout);
        // 到这是正式开始输入命令, req.user_name一直是登陆时的不变了

        // 构建就绪接收数组
        struct epoll_event events[10];
        // 开始监听

        int num = epoll_wait(epfd, events, 10, -1);

        // 遍历就绪集合
        for(int i = 0; i < num; i++){
            // 就绪fd
            int cfd = events[i].data.fd;
            if(cfd == socket_fd){

                //如果socket_fd可读，关闭socket_fd
                is_login = 0;
                close(socket_fd);
                epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &event);
                stdin_msg msg;
                bzero(&msg, sizeof(msg));
                //char buf[60] = {0};
                // 读标准输入
                char buf2[1024] = {0};
                int legal = 0;
                //read(STDIN_FILENO, buf, sizeof(buf));
                while(legal == 0){
                    fflush(stdin);
                    read(pipe_fd[0], &msg, sizeof(msg));
                    if(msg.signal == 2){
                        //有退出信号
                        for(int i=0;i<pthread_info->length;i++){
                            if(pthread_info->status[i]==1){
                                pthread_cancel(pthread_info->thread_ids[i]);
                            }
                        }
                        for(int i=0;i<pthread_info->length;i++){
                            if(pthread_info->status[i]==1){
                                pthread_join(pthread_info->thread_ids[i],NULL);
                            }
                        }
                        // 线程退出，客户端退出
                        exit(1);
                    }
                    strcpy(buf2, msg.buf);
                    if(stdin_check(msg.buf, req) == 0){
                        legal = 1;
                        printf("legal: %d\n",legal);
                    }
                    fflush(stdin);
                }
                int socket_fd = socket(AF_INET, SOCK_STREAM, 0);

                connect(socket_fd, (struct sockaddr *)&addr, sizeof(addr));

                event.data.fd = socket_fd;
                epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &event);
                req->flag = RECONNECT;
                int ret = send(socket_fd, req, sizeof(request_t), 0);

                ret = analyze_cmd(socket_fd,buf2,req,pthread_info);

                if (ret == -1){
                    printf("服务器响应错误\n");
                }
                if (ret == 1){
                    printf("非法命令, 请重新输入.\n");
                }
                if (ret == 2){
                    // 退出
                    exit(1);
                }

                if(ret == 3){
                    printf("服务器响应错误\n");
                }

                is_login = 1;

                printf("重新连接成功！\n");
                fflush(stdin);

            }
            if(cfd == pipe_fd[0]){
                // 读标准输入
                stdin_msg msg;
                bzero(&msg, sizeof(msg));

                read(pipe_fd[0], &msg, sizeof(msg));
                if(msg.signal == 2){
                     //有退出信号
                    for(int i=0;i<pthread_info->length;i++){
                        if(pthread_info->status[i]==1){
                            pthread_cancel(pthread_info->thread_ids[i]);
                        }
                    }
                    for(int i=0;i<pthread_info->length;i++){
                        if(pthread_info->status[i]==1){
                            pthread_join(pthread_info->thread_ids[i],NULL);
                        }
                    }
                    // 线程退出，客户端退出
                    exit(1);
                }
                //printf("buf : %s\n", buf);
                // 进行命令分析->拼接报文->发送报文
                int ret = analyze_cmd(socket_fd, msg.buf, req,pthread_info);
                if (ret == -1){
                    printf("服务器响应错误\n");
                    continue;
                }
                if (ret == 1){
                    printf("非法命令, 请重新输入.\n");
                    continue;
                }
                if (ret == 2){
                    // 退出
                    exit(1);
                }
                if (ret == 3){
                    printf("无可用子线程， 文件传输失败\n");
                    continue;
                }

            }
        }

    }

    free(pthread_info);
    free(req);
    free(res);
    close(socket_fd);
    return 0;
}
